home *** CD-ROM | disk | FTP | other *** search
- /* context.c - X context management
- *
- * Raster graphics library
- *
- * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <config.h>
-
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xatom.h>
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
-
- #include <math.h>
-
- #include "StdCmap.h"
-
- #include "wraster.h"
-
-
- extern void _wraster_change_filter(int type);
-
-
- static Bool bestContext(Display *dpy, int screen_number, RContext *context);
-
- static RContextAttributes DEFAULT_CONTEXT_ATTRIBS = {
- RC_UseSharedMemory|RC_RenderMode|RC_ColorsPerChannel, /* flags */
- RDitheredRendering, /* render_mode */
- 4, /* colors_per_channel */
- 0,
- 0,
- 0,
- 0,
- True, /* use_shared_memory */
- RMitchellFilter,
- RUseStdColormap
- };
-
-
-
- /*
- *
- * Colormap allocation for PseudoColor visuals:
- *
- *
- * switch standardColormap:
- * none:
- * allocate colors according to colors_per_channel
- *
- * best/default:
- * if there's a std colormap defined then use it
- *
- * else
- * create a std colormap and set it
- */
-
-
-
-
- /*
- *----------------------------------------------------------------------
- * allocateStandardPseudoColor
- * Creates the internal colormap for PseudoColor, setting the
- * color values according to the supplied standard colormap.
- *
- * Returns: -
- *
- * Side effects: -
- *
- * Notes: -
- *----------------------------------------------------------------------
- */
- static Bool
- allocateStandardPseudoColor(RContext *ctx, XStandardColormap *stdcmap)
- {
- int i;
-
- ctx->ncolors = stdcmap->red_max * stdcmap->red_mult
- + stdcmap->green_max * stdcmap->green_mult
- + stdcmap->blue_max * stdcmap->blue_mult + 1;
-
- if (ctx->ncolors <= 1) {
- RErrorCode = RERR_INTERNAL;
- puts("wraster: bad standard colormap");
-
- return False;
- }
-
- ctx->colors = malloc(sizeof(XColor)*ctx->ncolors);
- if (!ctx->colors) {
- RErrorCode = RERR_NOMEMORY;
-
- return False;
- }
-
- ctx->pixels = malloc(sizeof(unsigned long)*ctx->ncolors);
- if (!ctx->pixels) {
-
- free(ctx->colors);
- ctx->colors = NULL;
-
- RErrorCode = RERR_NOMEMORY;
-
- return False;
- }
-
-
- #define calc(max,mult) (((i / stdcmap->mult) % \
- (stdcmap->max + 1)) * 65535) / stdcmap->max
-
- for (i = 0; i < ctx->ncolors; i++) {
- ctx->colors[i].pixel = i + stdcmap->base_pixel;
- ctx->colors[i].red = calc(red_max, red_mult);
- ctx->colors[i].green = calc(green_max, green_mult);
- ctx->colors[i].blue = calc(blue_max, blue_mult);
-
- ctx->pixels[i] = ctx->colors[i].pixel;
- }
-
- #undef calc
-
- return True;
- }
-
-
- static Bool
- setupStandardColormap(RContext *ctx, Atom property)
- {
- if (!XmuLookupStandardColormap(ctx->dpy, ctx->screen_number,
- ctx->visual->visualid,
- ctx->depth, property,
- True, True)) {
- RErrorCode = RERR_STDCMAPFAIL;
-
- return False;
- }
- return True;
- }
-
-
-
-
-
-
-
-
-
- static Bool
- allocatePseudoColor(RContext *ctx)
- {
- XColor *colors;
- XColor avcolors[256];
- int avncolors;
- int i, ncolors, r, g, b;
- int retries;
- int cpc = ctx->attribs->colors_per_channel;
-
- ncolors = cpc * cpc * cpc;
-
- if (ncolors > (1<<ctx->depth)) {
- /* reduce colormap size */
- cpc = ctx->attribs->colors_per_channel = 1<<((int)ctx->depth/3);
- ncolors = cpc * cpc * cpc;
- }
-
- assert(cpc >= 2 && ncolors <= (1<<ctx->depth));
-
- colors = malloc(sizeof(XColor)*ncolors);
- if (!colors) {
- RErrorCode = RERR_NOMEMORY;
- return False;
- }
-
- ctx->pixels = malloc(sizeof(unsigned long)*ncolors);
- if (!ctx->pixels) {
- free(colors);
- RErrorCode = RERR_NOMEMORY;
- return False;
- }
-
- i=0;
-
- if ((ctx->attribs->flags & RC_GammaCorrection) && ctx->attribs->rgamma > 0
- && ctx->attribs->ggamma > 0 && ctx->attribs->bgamma > 0) {
- double rg, gg, bg;
- double tmp;
-
- /* do gamma correction */
- rg = 1.0/ctx->attribs->rgamma;
- gg = 1.0/ctx->attribs->ggamma;
- bg = 1.0/ctx->attribs->bgamma;
- for (r=0; r<cpc; r++) {
- for (g=0; g<cpc; g++) {
- for (b=0; b<cpc; b++) {
- colors[i].red=(r*0xffff) / (cpc-1);
- colors[i].green=(g*0xffff) / (cpc-1);
- colors[i].blue=(b*0xffff) / (cpc-1);
- colors[i].flags = DoRed|DoGreen|DoBlue;
-
- tmp = (double)colors[i].red / 65536.0;
- colors[i].red = (unsigned short)(65536.0*pow(tmp, rg));
-
- tmp = (double)colors[i].green / 65536.0;
- colors[i].green = (unsigned short)(65536.0*pow(tmp, gg));
-
- tmp = (double)colors[i].blue / 65536.0;
- colors[i].blue = (unsigned short)(65536.0*pow(tmp, bg));
-
- i++;
- }
- }
- }
-
- } else {
- for (r=0; r<cpc; r++) {
- for (g=0; g<cpc; g++) {
- for (b=0; b<cpc; b++) {
- colors[i].red=(r*0xffff) / (cpc-1);
- colors[i].green=(g*0xffff) / (cpc-1);
- colors[i].blue=(b*0xffff) / (cpc-1);
- colors[i].flags = DoRed|DoGreen|DoBlue;
- i++;
- }
- }
- }
- }
- /* try to allocate the colors */
- for (i=0; i<ncolors; i++) {
- if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
- colors[i].flags = 0; /* failed */
- } else {
- colors[i].flags = DoRed|DoGreen|DoBlue;
- }
- }
- /* try to allocate close values for the colors that couldn't
- * be allocated before */
- avncolors = (1<<ctx->depth>256 ? 256 : 1<<ctx->depth);
- for (i=0; i<avncolors; i++) avcolors[i].pixel = i;
-
- XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
-
- for (i=0; i<ncolors; i++) {
- if (colors[i].flags==0) {
- int j;
- unsigned long cdiff=0xffffffff, diff;
- unsigned long closest=0;
-
- retries = 2;
-
- while (retries--) {
- /* find closest color */
- for (j=0; j<avncolors; j++) {
- r = (colors[i].red - avcolors[i].red)>>8;
- g = (colors[i].green - avcolors[i].green)>>8;
- b = (colors[i].blue - avcolors[i].blue)>>8;
- diff = r*r + g*g + b*b;
- if (diff<cdiff) {
- cdiff = diff;
- closest = j;
- }
- }
- /* allocate closest color found */
- colors[i].red = avcolors[closest].red;
- colors[i].green = avcolors[closest].green;
- colors[i].blue = avcolors[closest].blue;
- if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
- colors[i].flags = DoRed|DoGreen|DoBlue;
- break; /* succeeded, don't need to retry */
- }
- #ifdef DEBUG
- printf("close color allocation failed. Retrying...\n");
- #endif
- }
- }
- }
-
- ctx->colors = colors;
- ctx->ncolors = ncolors;
-
- /* fill the pixels shortcut array */
- for (i = 0; i < ncolors; i++) {
- ctx->pixels[i] = ctx->colors[i].pixel;
- }
-
- return True;
- }
-
-
- static XColor*
- allocateGrayScale(RContext *ctx)
- {
- XColor *colors;
- XColor avcolors[256];
- int avncolors;
- int i, ncolors, r, g, b;
- int retries;
- int cpc = ctx->attribs->colors_per_channel;
-
- ncolors = cpc * cpc * cpc;
-
- if (ctx->vclass == StaticGray) {
- /* we might as well use all grays */
- ncolors = 1<<ctx->depth;
- } else {
- if ( ncolors > (1<<ctx->depth) ) {
- /* reduce colormap size */
- cpc = ctx->attribs->colors_per_channel = 1<<((int)ctx->depth/3);
- ncolors = cpc * cpc * cpc;
- }
-
- assert(cpc >= 2 && ncolors <= (1<<ctx->depth));
- }
-
- if (ncolors>=256 && ctx->vclass==StaticGray) {
- /* don't need dithering for 256 levels of gray in StaticGray visual */
- ctx->attribs->render_mode = RBestMatchRendering;
- }
-
- colors = malloc(sizeof(XColor)*ncolors);
- if (!colors) {
- RErrorCode = RERR_NOMEMORY;
- return False;
- }
- for (i=0; i<ncolors; i++) {
- colors[i].red=(i*0xffff) / (ncolors-1);
- colors[i].green=(i*0xffff) / (ncolors-1);
- colors[i].blue=(i*0xffff) / (ncolors-1);
- colors[i].flags = DoRed|DoGreen|DoBlue;
- }
- /* try to allocate the colors */
- for (i=0; i<ncolors; i++) {
- #ifdef DEBUG
- printf("trying:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
- #endif
- if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) {
- colors[i].flags = 0; /* failed */
- #ifdef DEBUG
- printf("failed:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
- #endif
- } else {
- colors[i].flags = DoRed|DoGreen|DoBlue;
- #ifdef DEBUG
- printf("success:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue);
- #endif
- }
- }
- /* try to allocate close values for the colors that couldn't
- * be allocated before */
- avncolors = (1<<ctx->depth>256 ? 256 : 1<<ctx->depth);
- for (i=0; i<avncolors; i++) avcolors[i].pixel = i;
-
- XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors);
-
- for (i=0; i<ncolors; i++) {
- if (colors[i].flags==0) {
- int j;
- unsigned long cdiff=0xffffffff, diff;
- unsigned long closest=0;
-
- retries = 2;
-
- while (retries--) {
- /* find closest color */
- for (j=0; j<avncolors; j++) {
- r = (colors[i].red - avcolors[i].red)>>8;
- g = (colors[i].green - avcolors[i].green)>>8;
- b = (colors[i].blue - avcolors[i].blue)>>8;
- diff = r*r + g*g + b*b;
- if (diff<cdiff) {
- cdiff = diff;
- closest = j;
- }
- }
- /* allocate closest color found */
- #ifdef DEBUG
- printf("best match:%x,%x,%x => %x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue,avcolors[closest].red,avcolors[closest].green,avcolors[closest].blue);
- #endif
- colors[i].red = avcolors[closest].red;
- colors[i].green = avcolors[closest].green;
- colors[i].blue = avcolors[closest].blue;
- if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) {
- colors[i].flags = DoRed|DoGreen|DoBlue;
- break; /* succeeded, don't need to retry */
- }
- #ifdef DEBUG
- printf("close color allocation failed. Retrying...\n");
- #endif
- }
- }
- }
- return colors;
- }
-
-
- static Bool
- setupPseudoColorColormap(RContext *context)
- {
- Atom property = 0;
-
- if (context->attribs->standard_colormap_mode == RCreateStdColormap) {
- property = XInternAtom(context->dpy, "RGB_DEFAULT_MAP", False);
-
- if (!setupStandardColormap(context, property)) {
- return False;
- }
- }
-
- if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
- XStandardColormap *maps;
- int count, i;
-
- if (!property) {
- property = XInternAtom(context->dpy, "RGB_BEST_MAP", False);
- if (!XGetRGBColormaps(context->dpy,
- DefaultRootWindow(context->dpy),
- &maps, &count, property)) {
- maps = NULL;
- }
-
- if (!maps) {
- property = XInternAtom(context->dpy, "RGB_DEFAULT_MAP", False);
- if (!XGetRGBColormaps(context->dpy,
- DefaultRootWindow(context->dpy),
- &maps, &count, property)) {
- maps = NULL;
- }
- }
- } else {
- if (!XGetRGBColormaps(context->dpy,
- DefaultRootWindow(context->dpy),
- &maps, &count, property)) {
- maps = NULL;
- }
- }
-
- if (maps) {
- int theMap = -1;
-
- for (i = 0; i < count; i++) {
- if (maps[i].visualid == context->visual->visualid) {
- theMap = i;
- break;
- }
- }
-
- if (theMap < 0) {
- puts("wrlib: no std cmap found");
- }
-
- if (theMap >= 0
- && allocateStandardPseudoColor(context, &maps[theMap])) {
-
- context->std_rgb_map = XAllocStandardColormap();
-
- *context->std_rgb_map = maps[theMap];
-
- context->cmap = context->std_rgb_map->colormap;
-
- XFree(maps);
-
- return True;
- }
-
- XFree(maps);
- }
- }
-
- context->attribs->standard_colormap_mode = RIgnoreStdColormap;
-
- /* RIgnoreStdColormap and fallback */
- return allocatePseudoColor(context);
- }
-
-
-
-
- static char*
- mygetenv(char *var, int scr)
- {
- char *p;
- char varname[64];
-
- sprintf(varname, "%s%i", var, scr);
- p = getenv(varname);
- if (!p) {
- p = getenv(var);
- }
- return p;
- }
-
-
- static void
- gatherconfig(RContext *context, int screen_n)
- {
- char *ptr;
-
- ptr = mygetenv("WRASTER_GAMMA", screen_n);
- if (ptr) {
- float g1,g2,g3;
- if (sscanf(ptr, "%f/%f/%f", &g1, &g2, &g3)!=3
- || g1<=0.0 || g2<=0.0 || g3<=0.0) {
- printf("wrlib: invalid value(s) for gamma correction \"%s\"\n",
- ptr);
- } else {
- context->attribs->flags |= RC_GammaCorrection;
- context->attribs->rgamma = g1;
- context->attribs->ggamma = g2;
- context->attribs->bgamma = g3;
- }
- }
- ptr = mygetenv("WRASTER_COLOR_RESOLUTION", screen_n);
- if (ptr) {
- int i;
- if (sscanf(ptr, "%d", &i)!=1 || i<2 || i>6) {
- printf("wrlib: invalid value for color resolution \"%s\"\n",ptr);
- } else {
- context->attribs->flags |= RC_ColorsPerChannel;
- context->attribs->colors_per_channel = i;
- }
- }
-
- ptr = mygetenv("WRASTER_OPTIMIZE_FOR_SPEED", screen_n);
- if (ptr) {
- context->flags.optimize_for_speed = 1;
- } else {
- context->flags.optimize_for_speed = 0;
- }
-
- }
-
-
- static void
- getColormap(RContext *context, int screen_number)
- {
- Colormap cmap = None;
- XStandardColormap *cmaps;
- int ncmaps, i;
-
- if (XGetRGBColormaps(context->dpy,
- RootWindow(context->dpy, screen_number),
- &cmaps, &ncmaps, XA_RGB_DEFAULT_MAP)) {
- for (i=0; i<ncmaps; ++i) {
- if (cmaps[i].visualid == context->visual->visualid) {
- puts("ACHOU");
- cmap = cmaps[i].colormap;
- break;
- }
- }
- XFree(cmaps);
- }
- if (cmap == None) {
- XColor color;
-
- cmap = XCreateColormap(context->dpy,
- RootWindow(context->dpy, screen_number),
- context->visual, AllocNone);
-
- color.red = color.green = color.blue = 0;
- XAllocColor(context->dpy, cmap, &color);
- context->black = color.pixel;
-
- color.red = color.green = color.blue = 0xffff;
- XAllocColor(context->dpy, cmap, &color);
- context->white = color.pixel;
-
- }
- context->cmap = cmap;
- }
-
-
- static int
- count_offset(unsigned long mask)
- {
- int i;
-
- i=0;
- while ((mask & 1)==0) {
- i++;
- mask = mask >> 1;
- }
- return i;
- }
-
-
- RContext*
- RCreateContext(Display *dpy, int screen_number, RContextAttributes *attribs)
- {
- RContext *context;
- XGCValues gcv;
-
-
- context = malloc(sizeof(RContext));
- if (!context) {
- RErrorCode = RERR_NOMEMORY;
- return NULL;
- }
- memset(context, 0, sizeof(RContext));
-
- context->dpy = dpy;
-
- context->screen_number = screen_number;
-
- context->attribs = malloc(sizeof(RContextAttributes));
- if (!context->attribs) {
- free(context);
- RErrorCode = RERR_NOMEMORY;
- return NULL;
- }
- if (!attribs)
- *context->attribs = DEFAULT_CONTEXT_ATTRIBS;
- else
- *context->attribs = *attribs;
-
- if (!(context->attribs->flags & RC_StandardColormap)) {
- context->attribs->standard_colormap_mode = RUseStdColormap;
- }
-
- if (!(context->attribs->flags & RC_ScalingFilter)) {
- context->attribs->flags |= RC_ScalingFilter;
- context->attribs->scaling_filter = RMitchellFilter;
- }
-
- /* get configuration from environment variables */
- gatherconfig(context, screen_number);
- #ifndef BENCH
- _wraster_change_filter(context->attribs->scaling_filter);
- #endif
- if ((context->attribs->flags & RC_VisualID)) {
- XVisualInfo *vinfo, templ;
- int nret;
-
- templ.screen = screen_number;
- templ.visualid = context->attribs->visualid;
- vinfo = XGetVisualInfo(context->dpy, VisualIDMask|VisualScreenMask,
- &templ, &nret);
- if (!vinfo || nret==0) {
- free(context);
- RErrorCode = RERR_BADVISUALID;
- return NULL;
- }
-
- if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) {
- context->attribs->flags |= RC_DefaultVisual;
- } else {
- XSetWindowAttributes attr;
- unsigned long mask;
-
- context->visual = vinfo[0].visual;
- context->depth = vinfo[0].depth;
- context->vclass = vinfo[0].class;
- getColormap(context, screen_number);
- attr.colormap = context->cmap;
- attr.override_redirect = True;
- attr.border_pixel = 0;
- attr.background_pixel = 0;
- mask = CWBorderPixel|CWColormap|CWOverrideRedirect|CWBackPixel;
- context->drawable =
- XCreateWindow(dpy, RootWindow(dpy, screen_number), 1, 1,
- 1, 1, 0, context->depth, CopyFromParent,
- context->visual, mask, &attr);
- /* XSetWindowColormap(dpy, context->drawable, attr.colormap);*/
- }
- XFree(vinfo);
- }
-
- /* use default */
- if (!context->visual) {
- if ((context->attribs->flags & RC_DefaultVisual)
- || !bestContext(dpy, screen_number, context)) {
- context->visual = DefaultVisual(dpy, screen_number);
- context->depth = DefaultDepth(dpy, screen_number);
- context->cmap = DefaultColormap(dpy, screen_number);
- context->drawable = RootWindow(dpy, screen_number);
- context->black = BlackPixel(dpy, screen_number);
- context->white = WhitePixel(dpy, screen_number);
- context->vclass = context->visual->class;
- }
- }
-
- gcv.function = GXcopy;
- gcv.graphics_exposures = False;
- context->copy_gc = XCreateGC(dpy, context->drawable, GCFunction
- |GCGraphicsExposures, &gcv);
-
- if (context->vclass == PseudoColor || context->vclass == StaticColor) {
-
- if (!setupPseudoColorColormap(context)) {
- return NULL;
- }
-
- } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
- context->colors = allocateGrayScale(context);
- if (!context->colors) {
- return NULL;
- }
- } else if (context->vclass == TrueColor) {
- /* calc offsets to create a TrueColor pixel */
- context->red_offset = count_offset(context->visual->red_mask);
- context->green_offset = count_offset(context->visual->green_mask);
- context->blue_offset = count_offset(context->visual->blue_mask);
- /* disable dithering on 24 bits visuals */
- if (context->depth >= 24)
- context->attribs->render_mode = RBestMatchRendering;
- }
-
- /* check avaiability of MIT-SHM */
- #ifdef XSHM
- if (!(context->attribs->flags & RC_UseSharedMemory)) {
- context->attribs->flags |= RC_UseSharedMemory;
- context->attribs->use_shared_memory = True;
- }
-
- if (context->attribs->use_shared_memory) {
- int major, minor;
- Bool sharedPixmaps;
-
- context->flags.use_shared_pixmap = 0;
-
- if (!XShmQueryVersion(context->dpy, &major, &minor, &sharedPixmaps)) {
- context->attribs->use_shared_memory = False;
- } else {
- if (XShmPixmapFormat(context->dpy)==ZPixmap)
- context->flags.use_shared_pixmap = sharedPixmaps;
- }
- }
- #endif
-
- return context;
- }
-
-
- static Bool
- bestContext(Display *dpy, int screen_number, RContext *context)
- {
- XVisualInfo *vinfo=NULL, rvinfo;
- int best = -1, numvis, i;
- long flags;
- XSetWindowAttributes attr;
-
- rvinfo.class = TrueColor;
- rvinfo.screen = screen_number;
- flags = VisualClassMask | VisualScreenMask;
-
- vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
- if (vinfo) { /* look for a TrueColor, 24-bit or more (pref 24) */
- for (i=numvis-1, best = -1; i>=0; i--) {
- if (vinfo[i].depth == 24) best = i;
- else if (vinfo[i].depth>24 && best<0) best = i;
- }
- }
-
- #if 0
- if (best == -1) { /* look for a DirectColor, 24-bit or more (pref 24) */
- rvinfo.class = DirectColor;
- if (vinfo) XFree((char *) vinfo);
- vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis);
- if (vinfo) {
- for (i=0, best = -1; i<numvis; i++) {
- if (vinfo[i].depth == 24) best = i;
- else if (vinfo[i].depth>24 && best<0) best = i;
- }
- }
- }
- #endif
- if (best > -1) {
- context->visual = vinfo[best].visual;
- context->depth = vinfo[best].depth;
- context->vclass = vinfo[best].class;
- getColormap(context, screen_number);
- attr.colormap = context->cmap;
- attr.override_redirect = True;
- attr.border_pixel = 0;
- context->drawable =
- XCreateWindow(dpy, RootWindow(dpy, screen_number),
- 1, 1, 1, 1, 0, context->depth,
- CopyFromParent, context->visual,
- CWBorderPixel|CWColormap|CWOverrideRedirect, &attr);
- /* XSetWindowColormap(dpy, context->drawable, context->cmap);*/
- }
- if (vinfo) XFree((char *) vinfo);
-
- if (best < 0)
- return False;
- else
- return True;
- }
-